package com.manage.util;

import com.alibaba.druid.pool.DruidDataSource;
import com.alibaba.druid.pool.DruidDataSourceFactory;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Properties;

/**
 * @author 汤奇
 * @version V1.0
 * @Project JavaWeb_Code
 * @Package cn.myutil
 * @Description:  使用德鲁伊连接池的JDBC工具类
 * @Date 2022/4/27 19:26
 */
/**
 * 数据库工具类: 将连接数据库的一些操作, 封装成工具方法, 方便连接数据库的时候使用
 *
 * 1. 提取了一些公用的方法
 *
 * 2. 将URL user pwd 信息 都使用配置文件管理
 * */
public class DruidUtil {
    //ThreadLocal: 可以实现线程之间的数据的安全. 可以使用该对象保存一个唯一的值.
    //一个ThreadLocal对象, 只能保存一个值
    //来保存唯一的一个 Connection
    public static ThreadLocal<Connection> local = new ThreadLocal<>();

    //定义德鲁伊的连接池数据源对象
    private static DruidDataSource dataSource;
    
    //提供对外的访问的接口
    public static DruidDataSource getDataSource(){
        return dataSource;
    }
    //读取配置文件的内容
    static {
        try {
            //容器
            Properties prop = new Properties();
            prop.load(DruidUtil.class.getClassLoader().getResourceAsStream("druid.prop"));
            //通过配置文件的容器去创建连接池数据源对象
            dataSource = (DruidDataSource)DruidDataSourceFactory.createDataSource(prop);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    //构造方法私有化
    private DruidUtil(){}

    /**
     * 创建连接对象
     * */
    public static Connection getConnection(){
        Connection conn = null;
        try {
            //ThreadLocal 中是否已经有了 Connection 对象
            conn = local.get();
            //如果conn 还没有
            if (conn == null) {
                //从数据连接池中取一个
                conn = dataSource.getConnection();
                //将生成的conn添加到ThreadLocal中
                local.set(conn);
            }
            return conn;
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        }
        return conn;
    }

    /**
     * 创建发送器对象
     * */
    public static PreparedStatement getStmt(Connection conn, String sql, Object ...params){
        PreparedStatement pstmt = null;
        try {
            pstmt = conn.prepareStatement(sql);
            //将传入的实参数据, 填充到SQL语句中的问号的位置
            for (int i = 0; i < params.length; i++) {
                //动态的填充
                pstmt.setObject(i+1,params[i]);
            }
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        }
        return pstmt;
    }

    /**
     * 关闭所有资源
     * */
    public static void closeAll(ResultSet rs, PreparedStatement pstmt, Connection conn){
        if (rs != null) {
            try {
                rs.close();
            } catch (SQLException throwables) {
                throwables.printStackTrace();
            }
        }

        if (pstmt != null) {
            try {
                pstmt.close();
            } catch (SQLException throwables) {
                throwables.printStackTrace();
            }
        }

        if (conn != null) {
            try {
                //在事务进行的过程中不能关闭连接
                if (conn.getAutoCommit()){ // true, 非事务进行中
                    conn.close();
                    //连接一旦关闭,要从 ThreadLocal 中移除
                    local.remove();
                }

            } catch (SQLException throwables) {
                throwables.printStackTrace();
            }
        }
    }
}
